package org.wsjy.util;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

/**
 * 
 * @Title:重新加载属性文件工具类
 * @Company:宝尊电子商务有限公司
 * @Description:更新properties以及xml文件不需要重启服务器，由spring配置文件进行注入
 * @Author:xiaozhou.zhou
 * @Since:2015年1月8日
 * @Copyright:Copyright (c) 2014
 * @ModifyDate:
 * @Version:1.1.0
 */
public class ReloadableProperties {

    private static final String PROPERTIES_SUFFIX = ".properties";

    private static final String XML_SUFFIX = ".xml";

    private final Map<String, PropertiesHolder> cachedProperties = new HashMap<String, PropertiesHolder>();

    long cacheMillis = -1;

    String[] fileNames;

    ResourceLoader resourceLoader = new DefaultResourceLoader();

    public void setCacheSeconds(int cacheSeconds) {
        this.cacheMillis = cacheSeconds * 1000;
    }

    public String[] getFileNames() {
        return fileNames;
    }

    public void setFileNames(String[] fileNames) {
        this.fileNames = fileNames;
    }

    public String getProperty(String key) {
        String result = null;
        for (String fileName : fileNames) {
            PropertiesHolder p = getProperties(fileName);
            result = p.getProperties().getProperty(key);
            if (null != result) {
                return result;
            }
        }
        return null;
    }

    public void refresCache() {
        cachedProperties.clear();
    }

    private PropertiesHolder getProperties(String fileName) {
        synchronized (cachedProperties) {
            PropertiesHolder h = cachedProperties.get(fileName);
            if (h != null && (h.getRefreshTimestamp() < 0 || h.getRefreshTimestamp() > System.currentTimeMillis() - cacheMillis)) {
                return h;
            }
            return reloadCache(fileName, h);
        }
    }

    private PropertiesHolder reloadCache(String filename, PropertiesHolder propHolder) {
        long refreshTimestamp = (this.cacheMillis < 0) ? -1 : System.currentTimeMillis();

        Resource resource = this.resourceLoader.getResource(filename + PROPERTIES_SUFFIX);
        if (!resource.exists()) {
            resource = this.resourceLoader.getResource(filename + XML_SUFFIX);
        }
        if (resource.exists()) {
            long fileTimestamp = -1;
            if (this.cacheMillis >= 0) {
                // Last-modified timestamp of file will just be read if caching with timeout.
                try {
                    fileTimestamp = resource.lastModified();
                    if (propHolder != null && propHolder.getFileTimestamp() == fileTimestamp) {
                        propHolder.setRefreshTimestamp(refreshTimestamp);
                        return propHolder;
                    }
                } catch (IOException ex) {
                    // Probably a class path resource: cache it forever.
                    fileTimestamp = -1;
                }
            }
            try {
                Properties props = new Properties();
                props.load(resource.getInputStream());
                propHolder = new PropertiesHolder(props, fileTimestamp);
            } catch (IOException ex) {
                // Empty holder representing "not valid".
                propHolder = new PropertiesHolder();
            }
        }

        else {
            // Resource does not exist.
            // Empty holder representing "not found".
            propHolder = new PropertiesHolder();
        }

        propHolder.setRefreshTimestamp(refreshTimestamp);
        this.cachedProperties.put(filename, propHolder);
        return propHolder;
    }

    class PropertiesHolder {
        Properties properties = new Properties();
        String fileName;
        long fileTimestamp = -1;
        long refreshTimestamp = -1;

        public PropertiesHolder() {
            super();
        }

        public PropertiesHolder(Properties properties, long fileTimestamp) {
            super();
            this.properties = properties;
            this.fileTimestamp = fileTimestamp;
        }

        public Properties getProperties() {
            return properties;
        }

        public void setProperties(Properties properties) {
            this.properties = properties;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public long getFileTimestamp() {
            return fileTimestamp;
        }

        public void setFileTimestamp(long fileTimestamp) {
            this.fileTimestamp = fileTimestamp;
        }

        public long getRefreshTimestamp() {
            return refreshTimestamp;
        }

        public void setRefreshTimestamp(long refreshTimestamp) {
            this.refreshTimestamp = refreshTimestamp;
        }

    }

}
